home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Magnum One
/
Magnum One (Mid-American Digital) (Disc Manufacturing).iso
/
d3
/
ddjhptxt.arc
/
MISCHEL.LST
< prev
next >
Wrap
File List
|
1990-06-05
|
21KB
|
518 lines
LISTING ONE
name iter
page ,132
title 'ITER - Enhanced MS-DOS command line processor'
;
; ITER.ASM
;
; Copyright 1989, Jim Mischel
;
; This program provides enhanced command line processing for MS-DOS.
; Uses the external GETARG module for command line generation.
;
; Sample make file:
;
; # iter.mak - build iter.exe from iter.asm and getarg.asm
; .asm.obj:
; tasm $<
;
; iter.exe: iter.obj getarg.obj
; tlink iter getarg
;
ideal ;use TASM ideal mode
locals
dosseg
model small
stack 0100h
cr equ 0dh ;ASCII Carriage Return
lf equ 0ah ;ASCII Line Feed
DataSeg
cmd_adr dw ? ;store address of parsed com-
mand line
psp_seg dw ? ;PSP segment
comspec db 128 dup (?) ;local storage for value of
COMSPEC
cmd_length db 0," /C" ;command line length
cmd_args db 124 dup (?) ;and arguments
dw ? ;extra space for CR/LF/$
com_var db "COMSPEC=",0
iter_msg db " ITER>> $"
errmsg db "Command line error. Program
aborted",cr,lf,'$'
no_comspec db "ERROR: No COMSPEC environment variable."
db " Program Aborted",cr,lf,'$'
params dw 0
pm_cmd dw offset cmd_length ;seg:offset of command line
dw seg cmd_length
dd -1 ;default FCB #1
dd -1 ;default FCB #2
CodeSeg
extrn parse_cmdlin:proc ;getarg.asm
extrn get_cmdlin:proc ;getarg.asm
stk_seg dw ? ;save stack segment
stk_ptr dw ? ;save stack pointer
proc main
mov ax,ds ;get psp segment
mov dx,@data
mov ds,dx ;DS is local data segment
mov [psp_seg],ax ;save psp seg
cli
mov ss,dx ;setup stack
mov sp,stack
sti
;adjust memory allocation
mov es,ax ;psp segment in ES
mov bx,stack ;calculate #paragraphs needed
rept 4
shr bx,1
endm
inc bx
add bx,dx ;add data segment value
sub bx,ax ;and subtract PSP segment value
mov ah,4ah
int 21h
call near ptr get_comspec ;get COMSPEC environment variable
mov dx,offset no_comspec
jc main_error ;if C set then no comspec var
mov si,0081h ;command line starts at 0081h
mov ds,[psp_seg]
call parse_cmdlin ;parse the command line
mov dx,@data
mov ds,dx ;ds now points to local data segment
or ax,ax ;if the parse returns AX=0,
mov dx,offset errmsg
jz main_error ;then some error occured
mov [cmd_adr],ax ;save address of parsed command line
@@loop: mov si,[cmd_adr] ;command line address in DS:SI
call get_cmdlin ;get next command line
or ax,ax ;if AX=0,
jz main_exit ;then no more command lines to process
mov si,ax ;si is command line
mov di,offset cmd_args
mov bl,2 ;command length + 2
@@lp1: lodsb ;copy command line to cmd_args
stosb
inc bl ;and keep track of count
or al,al
jnz @@lp1
mov [cmd_length],bl ;save command length
mov [word ptr di-1],0d0ah ;terminate string with CR/LF/$
mov [byte ptr di+1],'$'
mov ah,9
mov dx,offset iter_msg ;output the "ITER>>"
int 21h
mov ah,9
mov dx,offset cmd_args ;and the command line
int 21h
push ds ;save segment registers
push es
mov [cs:stk_seg],ss ;and stack
mov [cs:stk_ptr],sp
mov dx,offset comspec
mov bx,offset params
mov ax,4b00h ;use DOS EXEC function
int 21h ;to do the command
mov ss,[cs:stk_seg] ;restore stack
mov sp,[cs:stk_ptr]
pop es ;and segment registers
pop ds
jmp short @@loop
main_error: ;some error occured in parse
mov dx,offset errmsg
mov ah,9
int 21h ;output error message
mov al,01 ;and set error status
main_exit: ;arrive here with return code in AL
mov ah,4ch
int 21h
endp main
;
; GET_COMSPEC
; Attempts to find the COMSPEC environment variable in the program's
; environment. If found, the value of the variable is copied to the
; local comspec data area.
;
; Returns Carry = 0 on success
; Carry = 1 on failure
;
proc get_comspec
mov es,[psp_seg]
mov es,[word ptr es:002ch] ;get environment segment
xor di,di ;ES:DI is environment pointer
gcom1: mov si,offset com_var ;DS:SI is string to match
cmp [byte ptr es:di],0 ;if this byte is 0
jnz gcom2 ;then there's no COMSPEC variable
stc ;so set carry to indicate failure
ret ;and exit
gcom2: lodsb ;get next character in vari-
able name
or al,al ;if it's 0
jz gcom4 ;then we've found the variable
cmp al,[byte ptr es:di] ;otherwise see if this char matches
jnz gcom3 ;the next char in environment
inc di ;and if so,
jmp short gcom2 ;continue with next character
; Unmatched variable. Go to end of this one & start over
gcom3: xor al,al ;gonna look for NUL terminator
mov cx,-1
cld
repnz scasb
jmp short gcom1
gcom4: mov si,offset comspec ;copy variable value from en-
vironment
@@loop: mov al,[byte ptr es:di] ;to local COMSPEC data area
mov [byte ptr si],al
inc si
inc di
or al,al
jnz @@loop
ret
endp get_comspec
end
LISTING TWO
name getarg
page ,132
title 'GETARG - command line generation module'
;
; GETARG.ASM
;
; Copyright 1989, Jim Mischel
;
; This module provides command line iteration processing for MS-DOS
; applications.
;
ideal ;use TASM ideal mode
locals
model small
cr equ 0dh ;ASCII Carriage Return
space equ ' ' ;ASCII Space
tab equ 9 ;ASCII Tab
hispace equ ' ' + 80h ;Flag space, argument separa-
tor
lpar equ '(' + 80h ;Flag left paren, start of iter list
rpar equ ')' + 80h ;Flag right paren, end of iter list
in_quote equ 1 ;mask for in-quote flag
in_space equ 2 ;mask for in-space flag
DataSeg
newcmd db 129 dup (?) ;storage for parsed command
line
cmdlin db 129 dup (?) ;storage for generated command
line
CodeSeg
public parse_cmdlin
public get_cmdlin
;
; PARSE_CMDLIN
; Converts command line into form used by GET_CMDLIN and returns a pointer
; to the parsed command line in AX. Returns AX = 0 on error.
;
; Call with DS:SI pointing to the command line to be parsed.
;
; BP, SP, CS, DS, and SS are preserved. Other registers may be trashed.
;
proc parse_cmdlin
cld
mov di,offset newcmd ;es:di is new command line
mov ax,seg newcmd
mov es,ax
@@skip: lodsb ;skip over leading white space
cmp al,space
jz @@skip
cmp al,tab
jz @@skip
xor dx,dx ;dh is quote/space flag
;dl is left paren count
jmp short pc2 ;jump around first load
pc1: lodsb
pc2: cmp al,cr ;if char is CR or NUL
jz pc_done
or al,al
jz pc_done ;then we're at end
test dh,in_quote ;if in quote
jz pc3
stosb ;store in new command line
cmp al,'"' ;and check for end of quote
jnz pc1
and dh,not in_quote
jmp short pc1
pc3: cmp al,space ;check for separator character
jz do_space
cmp al,tab
jz do_space
cmp al,','
jnz pc4
do_space:
test dh,in_space ;if already in space
jnz pc1 ;then ignore
mov al,space
stosb ;otherwise store a space
or dh,in_space ;and set the space flag
jmp short pc1
pc4: and dh,not in_space ;re-set space flag
cmp al,'"' ;if character is quote
jnz pc5
stosb ;then store it
or dh,in_quote ;and set the quote flag
jmp short pc1
pc5: cmp al,'(' ;if char is left paren
jnz pc7
or dl,dl ;if left paren flag is already set
jnz error_return ;then we've got nested iteration
mov al,LPAR ;otherwise store a left paren
stosb ;with the high bit set
inc dl ;and set the left paren flag
jmp short pc1
pc7: cmp al,')' ;if right paren
jnz pc8
or dl,dl ;check for left paren flag
jz error_return ;unbalanced if it's not set
xor dl,dl ;re-set left paren flag
pc8: stosb ;store the character
jmp short pc1
pc_done:
mov [byte ptr es:di],0 ;terminate string
cmp al,cr ;check for end of string
jz ckq
or al,al ;if not at end of string
jnz error_return ;then error
ckq: or dh,dl ;check for unterminated strings
;and unbalanced parenthesis
jnz error_return
good_return:
mov ax,offset newcmd ;return pointer to newcmd
jmp short pc_ret
error_return:
xor ax,ax ;return error status
pc_ret: ret
endp parse_cmdlin
;
; UPDATE_ITEM
; Update iteration pointers on the next argument in the command line.
;
; Call with DS:SI pointing to argument to update.
;
; Returns AH = 1 (and Z flag cleared) if iteration list updated
; AH = 0 (and Z flag set) if not.
;
; This is a recursive function.
;
proc update_item
xor ax,ax ;AH is quote flag
mov bx,ax ;BX is list head
mov cx,ax ;CX is first item
mov di,ax ;DI is next item
ui1: lodsb ;get next character
or al,al ;if NUL,
jz ret_0 ;then we're done
cmp al,'"' ;if quote
jnz ui2
not ah ;then flop quote flag
jmp short ui1
ui2: or ah,ah ;if quote flag is set
jnz ui1 ;then just continue
cmp al,'(' ;if left paren
jnz ui3
ui21: mov bx,si ;then save list head pointer
jmp short ui1
ui3: cmp al,lpar ;if flagged left paren
jnz ui4
mov cx,si ;then save first item pointer
mov bx,si ;and list head pointer too
jmp short ui1
ui4: cmp al,hispace ;if high space
jnz ui5
mov cx,si ;then save first item pointer
jmp short ui1
ui5: cmp al,space ;if char is space
jnz ui7
or bx,bx ;and list head is NULL
jz short ret_0 ;then return 0
or cx,cx ;otherwise if first item is not NULL
jz ui1
or di,di ;and next item is NULL
jnz ui1
mov di,si ;then save next item pointer
jmp short ui1
ui7: and al,7fh ;strip high bit
cmp al,')' ;if character is right paren
jnz ui1
or di,di ;if next_item is NULL
jnz ui10
mov di,si ;then save next item pointer
ui10: push bx ;save local variables
push cx
push di
call update_item ;update the item from here forward
pop di ;restore locals
pop cx
pop bx
jnz ui_ret ;if updated then exit
xchg bx,cx ;bx is first item, cx is list head
sub [byte ptr bx-1],80h ;otherwise clear flag on first item
xchg bx,cx ;put 'em back where they belong
mov al,[byte ptr di-1] ;get next item
and al,7fh
cmp al,')' ;if it's the end of an iteration list
jnz ui8
mov [byte ptr di-1],rpar ;then set the done flag
mov [byte ptr bx-1],lpar ;and re-initialize the list
ret_0: xor ah,ah ;0 means no update
ret
ui8: add [byte ptr di-1],80h ;not at end of list so set space flag
ret_1: mov ah,1 ;1 signifies update occured
or ah,ah ;set Z flag to reflect return status
ui_ret: ret
endp update_item
;
; NEXT_ITER
; Update the command line for the next iteration.
;
; Returns the last character scanned. If the last char scanned is
; 0 (the string terminator), then all command lines have been generated.
;
; Call with DS:SI pointing to the command line to be updated.
;
proc next_iter
push si ;save beginning of command line
@@loop: call update_item
cmp [byte ptr si],0
jnz @@loop ;update each item
pop si ;restore command line address
mov di,si ;save it here in case we need it
;
; If the string terminator (0) is found, then all command lines have
; been generated.
; If a right paren (unflagged) is found, then there's still more work to do.
;
@@lp1: lodsb
cmp al,')'
jz @@done
or al,al
jnz @@lp1
mov [byte ptr di],al ;end of command lines, store NUL
@@done: ret
endp next_iter
;
; GET_CMDLIN
; Generates the next command line and returns a pointer to it in AX
; Returns AX = 0 if all command lines have been generated.
;
; Call with DS:SI pointing to the parsed command line.
;
; BP, SP, SS and DS are saved by this routine. All other registers may
; be destroyed.
;
proc get_cmdlin
cmp [byte ptr si],0 ;if command line is empty
jnz gc1
xor ax,ax ;then return NULL
ret
cld ;gotta do this!
gc1: push si ;save command line address
mov ax,seg cmdlin
mov es,ax
mov di,offset cmdlin ;ES:DI is generated command line
mov dx,0200h ;dh is copy flag
;2 = unconditional copy
;1 = copy to end of arg
;0 = no copy
;dl is quote flag
gc2: lodsb ;get next character
or al,al ;if NUL,
jz gc_done
cmp al,cr ;or CR...
jz gc_done ;then we're done
or dl,dl ;otherwise, if in quote
jz gc4
or dh,dh ;and in copy
jz gc3
stosb ;then save the character
gc3: cmp al,'"' ;if character is quote
jnz gc2
not dl ;then re-set quote flag
jmp short gc2
gc4: cmp al,'"' ;if character is quote
jnz gc5
not dl ;set the quote flag
or dh,dh ;if in copy
jz gc2
stosb ;then store the character
jmp short gc2
gc5: or dh,dh ;dispatch to proper routine
jz copy_0 ;depending on value of DH (copy flag)
cmp dh,1
jz copy_1
copy_2: cmp al,'(' ;if character is '('
jnz c21
xor dh,dh ;then clear copy flag
jmp short gc2
c21: cmp al,lpar ;if char is lpar
jz c22
cmp al,hispace ;or hispace
jnz c23
c22: mov dh,1 ;then set copy to 1
jmp short gc2
c23: stosb ;otherwise store the character
jmp short gc2
copy_1: cmp al,space ;if char is space
jnz c11
xor dh,dh ;then clear copy flag
jmp short gc2
c11: cmp al,')' ;if character is right paren
jz c12
cmp al,rpar ;or flagged right paren...
jnz c23 ;(it's neither, store and go)
c12: mov dh,2 ;...then set the copy flag
jmp short gc2
copy_0: cmp al,')' ;if character is not right
paren
jz c12
cmp al,rpar ;or flagged right paren
jz c12
cmp al,hispace ;if it's hispace
jz c22 ;then set copy to 1
jmp short gc2 ;otherwise just ignore it
gc_done: ;done generating command line
xor al,al
stosb ;terminate string with NUL byte
pop si ;restore command line address
call next_iter ;and update for next iteration
mov ax,offset cmdlin ;return address of...
ret ;... generated command line
endp get_cmdlin
end